/**
 * chenxitech.cn Inc.
 * Copyright (c) 2017-2017 All Rights Reserved.
 */
package com.zsc.common.web.filter;

import com.alibaba.fastjson.TypeReference;
import com.zsc.common.web.result.BaseResult;
import com.zsc.common.web.util.CodeEnum;
import com.zsc.common.web.util.JsonUtils;
import com.zsc.common.web.util.PrintLogUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author xbkaishui
 * @version $Id: LogFilter.java, v 0.1 2017-04-13 上午12:25 xbkaishui Exp $$
 */
public class LogFilter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(LogFilter.class);

    public void init(FilterConfig config) throws ServletException {
        // NOOP.
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        if (response.getCharacterEncoding() == null) {
            response.setCharacterEncoding("UTF-8"); // Or whatever default. UTF-8 is good for World Domination.
        }
        if (!(request instanceof ContentCachingRequestWrapper)) {
            request = new ContentCachingRequestWrapper((HttpServletRequest) request);
        }
        if (!(response instanceof ContentCachingResponseWrapper)) {
            response = new ContentCachingResponseWrapper((HttpServletResponse) response);
        }
        try {
            chain.doFilter(request, response);
        } finally {
            String url = ((HttpServletRequest) request).getRequestURI();
            PrintLogUtil.debug(logger, "Url: ", url);
            String requestContent = getRequestContent(request);
            String responseContent = getResponseContent(response);
            PrintLogUtil.debug(logger, "request: ", requestContent);
            PrintLogUtil.debug(logger, "response:  ", responseContent); // Do your logging job here. This is just a basic example.
            BaseResult result = JsonUtils.fromJson(responseContent, new TypeReference<BaseResult>() {
            });
            String isSuccess = "false";
            if (result.getCode() == CodeEnum.code8200.getCode()) {
                isSuccess = "true";
            }
            PrintLogUtil.logOperation(logger, url, requestContent, isSuccess);
        }
    }

    private String getRequestContent(ServletRequest request) {
        ContentCachingRequestWrapper wrapper =
                WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            String payload = bytesToString(wrapper.getCharacterEncoding(), buf);
            if (payload != null) return payload;
        }
        return "";
    }

    private String getResponseContent(ServletResponse response) {
        ContentCachingResponseWrapper wrapper =
                WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if (wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            String payload = bytesToString(wrapper.getCharacterEncoding(), buf);
            try {
                wrapper.copyBodyToResponse();
            } catch (IOException e) {
                logger.error("getResponseContent error!",e);
            }
            if (payload != null) return payload;
        }
        return "";
    }

    private String bytesToString(String encode, byte[] buf) {
        if (buf.length > 0) {
            String payload;
            try {
                payload = new String(buf, encode);
            } catch (UnsupportedEncodingException ex) {
                payload = "[unknown]";
            }
            return payload;
        }
        return null;
    }

    public void destroy() {
        // NOOP.
    }
}
